-- 2022-8-2

--[[
    词法定界

    当编写一个被其他函数B包含的函数A时，被包含的函数A可以访问包含其的函数B的所有的局部变量，我们将这种特性称为词法定界
    虽然这种可见性规则听上去很明确，但实际上并非如此。
    词法定界外加嵌套的第一类值函数可以为编程语言提供强大的功能，但很多编程语言并不支持将这两者组合使用

    函数作为第一类值，能够逃逸出它们变量的原始定界范围

    简单的说，一个闭包就是一个函数外加能够使该函数正确访问非局部变量所需的其他机制

    从技术上将Lua语言只有闭包没有函数，函数本身只是闭包的一种原型
    不过尽管如此，只要不会引起混淆，我们就使用"函数"来指代闭包

    闭包在许多场合中均是一种有价值的工具，正如我们之前见到的，闭包在作为诸如sort这样的高阶函数的参数时就非常有用
    同样，闭包对于那些创建了其他函数的函数也很有用；这种机制使得Lua程序能够综合应用函数式编程世界中多种精妙的编程技巧

    闭包对于回调函数来说也很有用

    闭包在另一种不一样的场景下也非常有用，由于函数可以被保存在普通变量中，因此在lua语言在可以轻松定义函数，甚至是预定义函数
    这机制也正是lua语言灵活的原因之一
    通常，当重新定义一个函数的时候，我们需要在行动实现在调用原来那个函数
        例如
        local oldSin = math.sin
        math.sin = function(x)
            return oldSin(x*(math.pi/180))
        end
        另一种更加清晰的写法是
        do
            local oldSin = math.sin
            math.sin = function(x)
                return oldSin(x*(math.pi/180))
            end
        end
    上述代码使用了do代码来限制局部变量oldSin的作用范围；根据可见性规则，局部变量oldSin只在这段代码段中有效
    
    我们可以使用同样的技巧来创建安全的运行时环境，即所谓的沙盒
    当执行一些诸如从远程服务器上下载到的未受信任代码时，安全的运行时环境非常重要 
    do
        local oldOpen = io.open
        local access_OK = function (filename,mode)
            --checkaccess
        end
        io.open = function (filename,mode)
            if access_OK(filename,mode) then
                return oldOpen(filename,mode)
            else
                return nil,"access denied"
            end
        end
    end
    上述示例的巧妙之处在于，经过重定义之后，一个程序只能通过新的受限版本来调用原来未受限版本的io.open函数
    示例代码将原来不安全的版本保存未闭包的一个私有变量，该变量无法从外部访问
    通过这一技巧，就可以在保证简洁性和灵活性的前提下在Lua语言本身上构建Lua沙盒
    相对于提供一套大而全(one-size-fits-all)的解决方案，Lua语言提供的是一套"元机制"，
    借助这种机制可以根据特定的安全需求来裁剪具体的运行时环境
]]
